package com.hudson.plugin.server.hibernateDB.service.impl;

import com.hudson.plugin.server.hibernateDB.domain.dao.*;
import com.hudson.plugin.server.hibernateDB.internal.domain.entity.*;
import com.hudson.plugin.server.hibernateDB.service.ReportDBService;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * User: yuxinlei
 * Date: 4/13/11
 * Time: 1:43 PM
 */
public class ReportDBServiceImpl implements ReportDBService {
    private static final Logger logger = LoggerFactory.getLogger(ReportDBServiceImpl.class);

    private HudsonsDAOInterface hudsonDAO;

    private ViewsDAOInterface viewsDAO;

    private ProjectsDAOInterface projectsDAO;

    private BuildsDAOInterface buildsDAO;

    private BuildRelationsDAOInterface buildRelationsDAO;

    public Map<String, String> storeToDB(
            Map<String, Map<String, String>> valuePairsContainer) throws Exception {
        Map<String, String> commonValuePairs = valuePairsContainer.get("commonValuePairs");

        return storeCommonDataDB(commonValuePairs);
    }


    public Map<String, String> storeCommonDataDB(Map<String, String> valuePairs) throws Exception {
        logger.debug("start to store the hudson data in to database .");

        HudsonsEntity hudsonsEntity = updateOrCreateHudsonEntity(valuePairs);
        // ViewsEntity viewsEntity = updateOrCreateViewsEntity(valuePairs, hudsonsEntity);
        ProjectsEntity projectsEntity = updateOrCreateProjectsEntity(valuePairs, hudsonsEntity, null);

        BuildsEntity build = createBuildsEntity(valuePairs, hudsonsEntity, null, projectsEntity);
        updatePluginTable(valuePairs, hudsonsEntity, null, projectsEntity, build);
        logger.debug("start to retrive all the build in current project which id is "
                + projectsEntity.getId());
        List<String> numbers = getBuildsDAO().findProjectAllBuildsNumber(projectsEntity);
        String period = "100";
        String contains = "100";
        ObjectMapper mapper = new ObjectMapper();
        String jsonNumbers = mapper.writeValueAsString(numbers);
        Map<String, String> resultMap = new HashMap<String, String>();
        resultMap.put("numbers", jsonNumbers);
        resultMap.put("period", period);
        resultMap.put("contains", contains);
        return resultMap;
    }

    public void updatePluginTable(Map<String, String> valuePairs, HudsonsEntity hudsonsEntity, ViewsEntity viewsEntity, ProjectsEntity projectsEntity, BuildsEntity buildsEntity) throws Exception {

    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private HudsonsEntity updateOrCreateHudsonEntity(Map<String, String> valuePairs) throws Exception {
        logger.debug("start to updateOrCreateHudsonEntity .");
        Integer hudsonId;
        HudsonsEntity tempHudsonsEntity = new HudsonsEntity();
        tempHudsonsEntity.setSlaves(valuePairs.get("hudsonSlave"));
        tempHudsonsEntity.setDescription(valuePairs.get("teamFoundation"));
        tempHudsonsEntity.setUrl(valuePairs.get("hudsonUrl"));
        if (getHudsonDAO().findHudsonsEntity(valuePairs.get("hudsonUrl")).size() != 0) {

            hudsonId = getHudsonDAO().findHudsonsEntity(valuePairs.get("hudsonUrl")).get(0);
            //for update
            tempHudsonsEntity.setId(hudsonId);
            HudsonsEntity compareEntity = getHudsonDAO().findById(hudsonId);
            if (!tempHudsonsEntity.equals(compareEntity)) {
                logger.debug("start to update HudsonEntity .");
                getHudsonDAO().merge(tempHudsonsEntity);
            }
        } else {
            getHudsonDAO().merge(tempHudsonsEntity);
            hudsonId = getHudsonDAO().findHudsonsEntity(valuePairs.get("hudsonUrl")).get(0);
        }
        return getHudsonDAO().findById(hudsonId);

    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private ViewsEntity updateOrCreateViewsEntity(Map<String, String> valuePairs, HudsonsEntity hudsonsEntity) throws Exception {
        logger.debug("start to updateOrCreateViewsEntity .");
        Integer viewid;

        ViewsEntity tempViewsEntity = new ViewsEntity();
        tempViewsEntity.setVersion(valuePairs.get("icafeVersion"));
        tempViewsEntity.setViewName(valuePairs.get("viewName"));
        tempViewsEntity.setHudsonsByHudsonId(hudsonsEntity);
        tempViewsEntity.setIcafeProject(valuePairs.get("icafeProject"));
        tempViewsEntity.setModule(valuePairs.get("icafeModule"));
        tempViewsEntity.setUrl(valuePairs.get("viewUrl"));
        if (getViewsDAO().findViewsEntityByModuleAndIcafeProject(valuePairs.get("icafeModule"), valuePairs.get("icafeProject")).size() != 0) {
            viewid = getViewsDAO().findViewsEntityByModuleAndIcafeProject(valuePairs.get("icafeModule"), valuePairs.get("icafeProject")).get(0);
            //for update
            tempViewsEntity.setId(viewid);
            ViewsEntity compareEntity = getViewsDAO().findById(viewid);
            if (!tempViewsEntity.equals(compareEntity)) {
                logger.debug("start to update ViewsEntity .");
                getViewsDAO().merge(tempViewsEntity);
            }
        } else {

            getViewsDAO().merge(tempViewsEntity);
            viewid = getViewsDAO().findViewsEntityByModuleAndIcafeProject(valuePairs.get("icafeModule"), valuePairs.get("icafeProject")).get(0);
        }
        return getViewsDAO().findById(viewid);
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private ProjectsEntity updateOrCreateProjectsEntity(Map<String, String> valuePairs, HudsonsEntity hudsonsEntity, ViewsEntity viewsEntity) throws Exception {
        logger.debug("start to updateOrCreateProjectsEntity .");
        Integer projectId;
        ProjectsEntity tempProjectsEntity = new ProjectsEntity();
        tempProjectsEntity.setChildProjects(valuePairs.get("child_projects"));
        tempProjectsEntity.setParentProjects(valuePairs.get("parent_projct"));
        tempProjectsEntity.setProjectName(valuePairs.get("projectName"));
        tempProjectsEntity.setType(valuePairs.get("projectType"));
        tempProjectsEntity.setUrl(valuePairs.get("projectUrl"));
        //tempProjectsEntity.setViewsByViewId(viewsEntity);
        tempProjectsEntity.setHudsonsByHudsonId(hudsonsEntity);
        if (getProjectsDAO().findProjectsEntityByHudsonIdAndName(hudsonsEntity.getId(), valuePairs.get("projectName")).size() != 0) {

            projectId = getProjectsDAO().findProjectsEntityByHudsonIdAndName(hudsonsEntity.getId(), valuePairs.get("projectName")).get(0);

            //for update
            tempProjectsEntity.setId(projectId);
            ProjectsEntity compareEntity = getProjectsDAO().findById(projectId);
            if (!tempProjectsEntity.equals(compareEntity)) {
                logger.debug("start to update ProjectsEntity .");
                getProjectsDAO().merge(tempProjectsEntity);
            }
        } else {

            getProjectsDAO().merge(tempProjectsEntity);
            projectId = getProjectsDAO().findProjectsEntityByHudsonIdAndName(hudsonsEntity.getId(), valuePairs.get("projectName")).get(0);
        }
        return getProjectsDAO().findById(projectId);
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private BuildsEntity createBuildsEntity(Map<String, String> valuePairs, HudsonsEntity hudsonsEntity, ViewsEntity viewsEntity, ProjectsEntity projectsEntity) throws Exception {
        logger.debug("start to createBuildsEntity .");
        Integer buildId = 0;
        Integer parentBuildId = 0;
        BuildsEntity buildsEntity = new BuildsEntity();
        buildsEntity.setBuildDate(Timestamp.valueOf(valuePairs.get("build_data")));
        buildsEntity.setBuildOn(valuePairs.get("build_on"));
        buildsEntity.setBuildNum(Integer.parseInt(valuePairs.get("build_num")));
        //find the parent
        parentBuildId = findParentBuildId(valuePairs, hudsonsEntity, projectsEntity);
        BuildsEntity mostUpperBuildsEntity = null;

        if (parentBuildId != null) {
            Integer mostUpperBuildId = findMostUpperParentId(parentBuildId);
            mostUpperBuildsEntity = getBuildsDAO().findById(mostUpperBuildId);
            valuePairs.put("cause_action", mostUpperBuildsEntity.getCauseAction());
            valuePairs.put("cause_action_user", mostUpperBuildsEntity.getAuthor());
        }
        buildsEntity.setAuthor(valuePairs.get("cause_action_user"));
        buildsEntity.setCauseAction(valuePairs.get("cause_action"));
        buildsEntity.setDuration(Integer.parseInt(valuePairs.get("duration")));
        buildsEntity.setProjectsByProjectId(projectsEntity);
        buildsEntity.setResult(valuePairs.get("result"));
        buildsEntity.setFailcount(Integer.parseInt(valuePairs.get("failCount")));
        buildsEntity.setSkipcount(Integer.parseInt(valuePairs.get("skipCount")));
        buildsEntity.setTotalcount(Integer.parseInt(valuePairs.get("totalCount")));
        BuildsEntity buildsEntityTest = getBuildsDAO().merge(buildsEntity);
        buildId = getBuildsDAO().findBuildsByProjectIdAndBuildNumber(projectsEntity.getId(), valuePairs.get("build_num").trim().toString()).get(0);
        //buildsDAO.findById(buildId);

        // create the current build relationship
        if (parentBuildId != null)
            updateBuildRelationships(parentBuildId, buildId);
        return getBuildsDAO().findById(buildId);
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private Integer findParentBuildId(Map<String, String> valuePairs, HudsonsEntity hudsonsEntity, ProjectsEntity projectsEntity) throws Exception {
        try {
            StringBuffer causeActionString = new StringBuffer(valuePairs.get("cause_action"));
            Integer parentBuildId = 0;
            Integer startIndex = 0;
            Integer projectId = 0;
            if (causeActionString.indexOf("UpstreamCause by") != -1) {
                startIndex = causeActionString.indexOf("UpstreamCause by");
                if (startIndex != -1) {


                    //if does , then abstract out the jobName and the buildNumber
                    String jobName = causeActionString.substring(
                            causeActionString.indexOf("\"") + 1, causeActionString.lastIndexOf("\"")).trim();
                    String buildNumber = causeActionString.substring(
                            causeActionString.lastIndexOf("#"), causeActionString.length()).trim();
                    //find the parent project
                    if (getProjectsDAO().findProjectsEntityByHudsonIdAndName(hudsonsEntity.getId(), jobName).size() != 0)
                        projectId = getProjectsDAO().findProjectsEntityByHudsonIdAndName(hudsonsEntity.getId(), jobName).get(0);
                    else
                        return null;
                    //find the parent build id
                    for (Integer buildsEntityId : getBuildsDAO().findBuildsByProjectIdAndBuildNumber(projectId, buildNumber.replace("#", "").trim().toString())) {
                        parentBuildId = buildsEntityId;
                        break;
                    }
                    //justify if there have the build number we want .
                    if (parentBuildId == 0) {
                        return null;
                        //parentBuildId = createBuildsEntity(valuePairs, hudsonsEntity, null, projectsEntity).getId();
                    }

                }
                return parentBuildId;
            } else {
                return null;
            }
        } catch (Exception e) {

        }
        return null;
    }

    @Transactional(readOnly = false, propagation = Propagation.REQUIRED)
    private void updateBuildRelationships(Integer parentId, Integer selfId) throws Exception {
        BuildRelationsEntity buildRelationsEntity = new BuildRelationsEntity();
        buildRelationsEntity.setParentId(parentId);
        buildRelationsEntity.setChildId(selfId);
        getBuildRelationsDAO().merge(buildRelationsEntity);
    }

    private Integer findMostUpperParentId(Integer selfId) {
        List<Integer> parentIds = getBuildRelationsDAO().findParentIdByChildId(selfId);
        if (parentIds.size() == 0) {
            return selfId;
        } else {
            return findMostUpperParentId(parentIds.get(0));
        }
    }

    public HudsonsDAOInterface getHudsonDAO() {
        return hudsonDAO;
    }

    public void setHudsonDAO(HudsonsDAOInterface hudsonDAO) {
        this.hudsonDAO = hudsonDAO;
    }

    public ViewsDAOInterface getViewsDAO() {
        return viewsDAO;
    }

    public void setViewsDAO(ViewsDAOInterface viewsDAO) {
        this.viewsDAO = viewsDAO;
    }

    public ProjectsDAOInterface getProjectsDAO() {
        return projectsDAO;
    }

    public void setProjectsDAO(ProjectsDAOInterface projectsDAO) {
        this.projectsDAO = projectsDAO;
    }

    public BuildsDAOInterface getBuildsDAO() {
        return buildsDAO;
    }

    public void setBuildsDAO(BuildsDAOInterface buildsDAO) {
        this.buildsDAO = buildsDAO;
    }

    public BuildRelationsDAOInterface getBuildRelationsDAO() {
        return buildRelationsDAO;
    }

    public void setBuildRelationsDAO(BuildRelationsDAOInterface buildRelationsDAO) {
        this.buildRelationsDAO = buildRelationsDAO;
    }
}
